#ifndef BONE_H
#define BONE_H

#include <string>
using std::string;

class Bone
{
public:
	Bone() : parent(0), m_uiFlags(0), boneIndex(-1){}
	virtual ~Bone(void){}

	int GetBoneIndex() { return boneIndex; }
	std::string  GetBoneName() { return boneName; }

	void SetBoneIndex(int _boneIndex) { boneIndex = _boneIndex; }
	void SetBoneName(string _boneName) { boneName = _boneName; }

	Bone *GetParent(void){ return parent; }
	std::vector< Bone *> &GetChildren(void){ return vrgChildren; }

	Bone *AddChild( Bone *_node )
	{
		if( _node->GetParent() != 0 )
			return 0;

		_node->parent = this;
		vrgChildren.push_back( _node );
		return _node;
	}

	Bone* RemoveChild( Bone* _node )
	{
		if( _node->GetParent() != this )
			return 0;

		for( unsigned int i = 0; i < vrgChildren.size(); ++i )
		{
			if( vrgChildren[i] == _node )
			{
				vrgChildren.erase( vrgChildren.begin() + i );
				_node->parent = 0;
				return _node;
			}
		}

		return 0;
	}

	enum { DIRTY = 1 };

	void Update(void)
	{
		if( (m_uiFlags & DIRTY) == 0 )
		{
			m_uiFlags |= DIRTY;

			for( unsigned int i = 0; i < GetChildren().size(); ++i )
				((Bone *)GetChildren()[i])->Update();
		}
	}

	XMFLOAT4X4& GetLocalMat(void){ return localMat; }

	XMFLOAT4X4& GetWorldMat(void)
	{
		if( (m_uiFlags & DIRTY) != 0 )
		{
			Bone* parent = GetParent();
			Bone* thisDude = this;

			if( GetParent() != NULL )
			{
				XMMATRIX local = XMLoadFloat4x4(&localMat);
				XMFLOAT4X4 worldParentf = ((Bone*)GetParent())->GetWorldMat();
				XMMATRIX worldParent = XMLoadFloat4x4(&worldParentf);

				XMStoreFloat4x4(&worldMat, XMMatrixMultiply(local,worldParent));
			}
			else
				worldMat = localMat;

			m_uiFlags &= ~DIRTY;
		}

		return worldMat;
	}

private:
	int boneIndex;
	string boneName;

	XMFLOAT4X4 localMat;
	XMFLOAT4X4 worldMat;

	unsigned int m_uiFlags;

	Bone *parent;
	std::vector<Bone*> vrgChildren;
};

#endif